package com.psdi.physics;

import com.psdi.element.ElementObject;
import com.psdi.element.Position;
import com.psdi.element.Size;

import java.util.ArrayList;
import java.util.List;

/**
 * 碰撞系统类
 * 用于管理游戏中的碰撞检测
 * 使用枚举单例模式实现
 * 所有实现了Collider接口且被添加到碰撞系统中的元素在此处自动处理碰撞，调用碰撞元素双方的 onCollisionStay 方法
 */
public enum CollisionSystem {
    INSTANCE;

    private final List<Collider> colliders = new ArrayList<>();
    private final List<Collider> collidersToRemove = new ArrayList<>();
    /** 添加 Collider */
    public void addElement(Collider collider) {
        colliders.add(collider);
    }

    /** 移除死亡 Collider */
    public void removeDeadColliders() {
        // 收集需要移除的碰撞体
        for (Collider collider : colliders) {
            if (!collider.isAlive()) {
                collidersToRemove.add(collider);
            }
        }

        // 移除收集到的碰撞体
        colliders.removeAll(collidersToRemove);
        collidersToRemove.clear();
    }

    /** 检测碰撞 */
    public void detectCollisions() {
        removeDeadColliders(); // 先清理死亡元素
        // 双重循环检测碰撞（从后往前遍历，避免重复检测）
        for (int i = colliders.size() - 1; i >= 0; i--) {
            Collider collider1 = colliders.get(i);
            for (int j = i - 1; j >= 0; j--) {
                Collider collider2 = colliders.get(j);
                // 检查标签过滤
                if (shouldSkipCollision(collider1, collider2)) {
                    continue;
                }
                // 检测碰撞
                if (isCollide(collider1, collider2)) {
                    collider1.onCollisionStay((ElementObject) collider2);
                    collider2.onCollisionStay((ElementObject) collider1);
                }
            }
        }
    }

    /** 检查是否应跳过碰撞检测 */
    private boolean shouldSkipCollision(Collider a, Collider b) {
        // 如果 a 的过滤标签包含 b 的标签，或 b 的过滤标签包含 a 的标签，则跳过
        return a.colliderFilterTag().contains(b.colliderTag()) || b.colliderFilterTag().contains(a.colliderTag());
    }

    /** 检测两个 Collider 是否碰撞 */
    private boolean isCollide(Collider a, Collider b) {
        Size sizeA = a.colliderSize();
        Position posA = a.colliderPosition();
        Size sizeB = b.colliderSize();
        Position posB = b.colliderPosition();

        return posA.x < posB.x + sizeB.width &&
                posA.x + sizeA.width > posB.x &&
                posA.y < posB.y + sizeB.height &&
                posA.y + sizeA.height > posB.y;
    }
}